{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%%shell\n",
        "# Installs the latest dev build of TVM from PyPI. If you wish to build\n",
        "# from source, see https://tvm.apache.org/docs/install/from_source.html\n",
        "pip install apache-tvm --pre"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 1. microTVM CLI 工具\n",
        "**Author**: [Mehrdad Hessar](https://github.com/mehrdadh)\n",
        "\n",
        "本教程介绍了如何为微型设备编译小模型，构建在 Zephyr 平台上执行此模型的程序，使用 `tvmc micro` 命令刷写程序并运行该模型。在开始本教程之前，您需要安装 Python 和 Zephyr 依赖项。"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 安装 microTVM Python 依赖\n",
        "\n",
        "TVM 不包括用于 Python 串行通信的软件包，因此在使用 microTVM 之前，必须先安装。还需要 TFLite 来加载模型。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%%bash\n",
        "pip install pyserial==3.5 tflite==2.1"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 安装 Zephyr"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%%bash\n",
        "# Install west and ninja\n",
        "python3 -m pip install west\n",
        "apt-get install -y ninja-build\n",
        "\n",
        "# Install ZephyrProject\n",
        "ZEPHYR_PROJECT_PATH=\"/content/zephyrproject\"\n",
        "export ZEPHYR_BASE=${ZEPHYR_PROJECT_PATH}/zephyr\n",
        "west init ${ZEPHYR_PROJECT_PATH}\n",
        "cd ${ZEPHYR_BASE}\n",
        "git checkout v3.2-branch\n",
        "cd ..\n",
        "west update\n",
        "west zephyr-export\n",
        "chmod -R o+w ${ZEPHYR_PROJECT_PATH}\n",
        "\n",
        "# Install Zephyr SDK\n",
        "cd /content\n",
        "ZEPHYR_SDK_VERSION=\"0.15.2\"\n",
        "wget \"https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${ZEPHYR_SDK_VERSION}/zephyr-sdk-${ZEPHYR_SDK_VERSION}_linux-x86_64.tar.gz\"\n",
        "tar xvf \"zephyr-sdk-${ZEPHYR_SDK_VERSION}_linux-x86_64.tar.gz\"\n",
        "mv \"zephyr-sdk-${ZEPHYR_SDK_VERSION}\" zephyr-sdk\n",
        "rm \"zephyr-sdk-${ZEPHYR_SDK_VERSION}_linux-x86_64.tar.gz\"\n",
        "\n",
        "# Install python dependencies\n",
        "python3 -m pip install -r \"${ZEPHYR_BASE}/scripts/requirements.txt\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 使用 TVMC Micro\n",
        "\n",
        "TVMC 是作为 TVM Python 软件包的一部分安装的命令行工具。访问此软件包取决于您的机器设置。在许多情况下，您可以直接使用 ``tvmc`` 命令。或者，如果您的 Python 路径中有 TVM 作为 Python 模块，您可以使用 ``python -m tvm.driver.tvmc`` 命令访问此驱动程序。本教程将简单地使用名为 ``tvmc`` 的 TVMC 命令。\n",
        "\n",
        "\n",
        "\n",
        "要检查您的机器上是否安装了 TVMC 命令，您可以运行：\n",
        "\n",
        "```bash\n",
        "tvmc --help\n",
        "```\n",
        "\n",
        "要为 MicroTVM 编译模型，使用 ``tvmc compile`` 子命令。此命令的输出将与  ``tvmc micro`` 子命令一起在接下来的步骤中使用。您可以使用以下命令检查 TVMC Micro 的可用性：\n",
        "\n",
        "```bash\n",
        "tvmc micro --help\n",
        "```\n",
        "\n",
        "您可以使用 ``tvmc micro`` 执行的主要任务包括 ``create``、``build`` 和 ``flash``。要了解特定子命令下的选项，请使用 ``tvmc micro <subcommand> --help``。在本教程中，我们将使用每个子命令。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 获取微模型\n",
        "\n",
        "在本教程中，将使用 tflite micro 中的 Micro Speech 模型。Micro Speech 是一种深度可分离卷积层模型，用于识别语音中的关键词。\n",
        "\n",
        "在本教程中，将使用 tflite 格式的模型。\n",
        "\n",
        "```bash\n",
        "wget https://github.com/tensorflow/tflite-micro/raw/a56087ffa2703b4d5632f024a8a4c899815c31bb/tensorflow/lite/micro/examples/micro_speech/micro_speech.tflite\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 将 TFLite 模型编译为模型库格式。\n",
        "\n",
        "模型库格式（Model Library Format，简写为 MLF）是 TVM 为 micro 目标提供的输出格式。MLF 是 tarball，其中包含 TVM 编译器输出的每个部分的文件，可以在 TVM 环境之外的 micro 目标上使用。了解更多关于“模型库格式”的信息，请参考 [](model_library_format)。\n",
        "\n",
        "在这里，我们为 ``qemu_x86`` Zephyr板生成 MLF 文件。您可以选择使用 `aot` 或 `graph` 执行器类型来运行本教程，但我们建议在微小的 TVM 目标中使用 `aot`，因为 `aot` 使用静态内存分配的预先编译。要为 ``micro_speech`` tflite 模型生成 MLF 输出，请执行以下操作：\n",
        "\n",
        "```bash\n",
        "tvmc compile micro_speech.tflite \\\n",
        "    --target='c -keys=cpu -model=host' \\\n",
        "    --runtime=crt \\\n",
        "    --runtime-crt-system-lib 1 \\\n",
        "    --executor='aot' \\\n",
        "    --output model.tar \\\n",
        "    --output-format mlf \\\n",
        "    --pass-config tir.disable_vectorize=1\n",
        "```\n",
        "\n",
        "这将生成包含 TVM 编译器输出文件的 ``model.tar`` 文件。要针对不同的 Zephyr 设备运行此命令，您需要更新 ``target``。例如，对于 ``nrf5340dk_nrf5340_cpuapp`` 板，目标是 ``--target='c -keys=cpu -model=nrf5340dk'``。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 使用模型库格式创建 Zephyr 项目。\n",
        "\n",
        "为了生成 Zephyr 项目，使用 TVM Micro 子命令 ``create``。将 MLF 格式和项目路径传递给 ``create`` 子命令，以及项目选项。每个平台（Zephyr/Arduino）的项目选项在其项目 API 服务器文件中定义。要为不同的 Zephyr 板构建 Zephyr 项目，请更改 ``zephyr_board`` 项目选项。要生成 Zephyr 项目，请运行：\n",
        "\n",
        "```bash\n",
        "tvmc micro create \\\n",
        "    project \\\n",
        "    model.tar \\\n",
        "    zephyr \\\n",
        "    --project-option project_type=host_driven board=qemu_x86\n",
        "```\n",
        "\n",
        "这将为 ``qemu_x86`` Zephyr板生成 ``Host-Driven`` Zephyr 项目。在 Host-Driven 模板项目中，Graph 执行器将在主机上运行，并通过使用 RPC 机制向设备发出命令，在 Zephyr 设备上执行模型。阅读有关[Host-Driven Execution](https://tvm.apache.org/docs/arch/microtvm_design.html#host-driven-execution) 的更多信息。\n",
        "\n",
        "要获取有关TVMC Micro ``create`` 子命令的更多信息：\n",
        "\n",
        "```bash\n",
        "tvmc micro create --help\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 使用 TVMC Micro 构建和 Flash Zephyr 项目\n",
        "\n",
        "下一步是构建 Zephyr 项目，其中包括运行小型模型所生成的 TVM 代码、在主机驱动模式下运行模型的 Zephyr 模板代码以及 TVM 运行时源代码/头文件。要构建该项目：\n",
        "\n",
        "```bash\n",
        "tvmc micro build \\\n",
        "    project \\\n",
        "    zephyr\n",
        "```\n",
        "\n",
        "这将在 ``project`` 目录中构建项目，并在 ``project/build`` 下生成二进制文件。\n",
        "\n",
        "\n",
        "接下来，我们将 Zephyr 二进制文件烧录(flash)到 Zephyr 设备上。对于 ``qemu_x86`` Zephyr 开发板，此步骤实际上不会执行任何操作，因为将使用 QEMU，但对于物理硬件，您需要执行此步骤。\n",
        "\n",
        "```bash\n",
        "tvmc micro flash \\\n",
        "    project \\\n",
        "    zephyr\n",
        "```\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 在 Micro Target 运行微模型\n",
        "\n",
        "烧录设备后，编译的模型和 TVM RPC 服务器被编程到设备上。Zephyr 开发板正在等待主机打开通信通道。MicroTVM 设备通常使用串行通信（UART）进行通信。使用 TVMC 运行已烧录的模型，我们使用 ``tvmc run`` 子命令并传递 ``--device micro`` 来指定设备类型。该命令将打开通信通道，在主机上使用 ``Graph Executor`` 设置输入值并在设备上运行完整模型。然后它从设备获取输出。\n",
        "\n",
        "```bash\n",
        "tvmc run \\\n",
        "    --device micro \\\n",
        "    project \\\n",
        "    --fill-mode ones \\\n",
        "    --print-top 4\n",
        "```\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "具体来说，此命令将模型的输入设置为全为 1，并显示输出的四个值及其索引。\n",
        "\n",
        "```bash\n",
        "# Output:\n",
        "# INFO:__main__:b'[100%] [QEMU] CPU: qemu32,+nx,+pae\\n'\n",
        "# remote: microTVM Zephyr runtime - running\n",
        "# INFO:__main__:b'[100%] Built target run\\n'\n",
        "# [[   3    2    1    0]\n",
        "#  [ 113 -120 -121 -128]]\n",
        "```\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.11"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
